package com.jlpay.open.jlpay.sdk.java.http;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jlpay.open.jlpay.sdk.java.exception.HttpExecutionException;
import com.jlpay.open.jlpay.sdk.java.exception.HttpStatusCodeException;
import com.jlpay.open.jlpay.sdk.java.sign.SignVerifierManager;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangyongfeng
 * @date 2025/5/27
 */
public class ApacheHttpClientWrapper extends AbstractHttpClient {

    private final CloseableHttpClient httpClient;

    public ApacheHttpClientWrapper(final CloseableHttpClient httpClient,
            final SignVerifierManager signVerifierManager) {
        super(signVerifierManager);
        this.httpClient = httpClient;
    }

    @Override
    protected HttpResponse sendPost(HttpRequest httpRequest) {
        HttpPost post = new HttpPost(httpRequest.getUrl().toString());

        // 设置请求头
        httpRequest.getHeaders().forEach(post::setHeader);

        // 设置请求体
        if (httpRequest.getBody() != null) {
            HttpEntity entity = new ByteArrayEntity(
                    httpRequest.getBody().getBytes(StandardCharsets.UTF_8),
                    ContentType.APPLICATION_JSON
            );
            post.setEntity(entity);
        }

        try (CloseableHttpResponse response = httpClient.execute(post)) {
            HttpResponse httpResponse = buildHttpResponse(response);

            if (httpResponse.getStatusCode() != 200) {
                throw new HttpStatusCodeException(
                        httpResponse.getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }
    }

    @Override
    protected HttpResponse sendGet(HttpRequest httpRequest) {
        HttpGet get = new HttpGet(httpRequest.getUrl().toString());

        // 设置请求头
        httpRequest.getHeaders().forEach(get::setHeader);

        try (CloseableHttpResponse response = httpClient.execute(get)) {
            HttpResponse httpResponse = buildHttpResponse(response);

            if (httpResponse.getStatusCode() != 200) {
                throw new HttpStatusCodeException(
                        httpResponse.getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }
    }

    @Override
    public HttpResponse sendFromPost(MultipartHttpRequest httpRequest) {
        HttpPost post = new HttpPost(httpRequest.getUrl().toString());

        // 设置请求头
        httpRequest.getHeaders().forEach(post::setHeader);

        // 创建MultipartEntityBuilder
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

        // 添加meta部分
        ObjectNode meta = httpRequest.getMeta();
        builder.addTextBody("meta", meta.toString(), ContentType.APPLICATION_JSON);

        // 添加file部分
        byte[] fileContent = httpRequest.getFile();
        String filename = meta.get("filename").textValue();
        ContentType contentType = ContentType.create("application/octet-stream", StandardCharsets.UTF_8);
        builder.addBinaryBody("file", fileContent, contentType, filename);

        // 设置请求体
        HttpEntity entity = builder.build();
        post.setEntity(entity);

        // 设置Content-Type
        post.setHeader("Content-Type", entity.getContentType().getValue());

        try (CloseableHttpResponse response = httpClient.execute(post)) {
            HttpResponse httpResponse = buildHttpResponse(response);
            if (httpResponse.getStatusCode() != 200) {
                throw new HttpStatusCodeException(
                        response.getStatusLine().getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }
    }

    private HttpResponse buildHttpResponse(CloseableHttpResponse response) throws IOException {
        Map<String, String> headerMap = new HashMap<>();
        Arrays.stream(response.getAllHeaders()).forEach(header -> headerMap.put(header.getName(), header.getValue()));

        return HttpResponse.builder()
                .headers(headerMap)
                .body(getBody(response))
                .statusCode(response.getStatusLine().getStatusCode())
                .build();
    }

    private String getBody(CloseableHttpResponse response) throws IOException {
        if (response == null || response.getEntity() == null) {
            return null;
        }
        return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
    }
}
